/**
 * Copyright (c) 2014- 2015 YCY Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package com.jkwzms.system.resource.service;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.shiro.authz.permission.WildcardPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.jkwzms.common.entity.search.SearchOperator;
import com.jkwzms.common.entity.search.Searchable;
import com.jkwzms.common.inject.annotation.BaseComponent;
import com.jkwzms.common.plugin.serivce.BaseTreeableService;
import com.jkwzms.system.auth.service.UserAuthService;
import com.jkwzms.system.resource.entity.Resource;
import com.jkwzms.system.resource.entity.tmp.Menu;
import com.jkwzms.system.resource.entity.tmp.Treegrid;
import com.jkwzms.system.resource.repository.ResourceRepository;
import com.jkwzms.system.user.entity.User;

/**
 * <p>
 * User: Jack Liang
 * <p>
 * Date: 13-2-4 下午3:01
 * <p>
 * Version:1.0.0
 */
@Service
public class ResourceService extends BaseTreeableService<Resource, Long> {

    @Autowired
    @BaseComponent
    private ResourceRepository resourceRepository;

    @Autowired
    private UserAuthService    userAuthService;

    /**
     * 得到真实的资源标识 即 父亲:儿子
     * 
     * @param resource
     * @return
     */
    public String findActualResourceIdentity(Resource resource) {

        if (resource == null) {
            return null;
        }

        StringBuilder s = new StringBuilder(resource.getIdentity() == null ? "" : resource.getIdentity());

        // 判断是否存在资源标识
        boolean hasResourceIdentity = !StringUtils.isEmpty(resource.getIdentity());

        Resource parent = findOne(resource.getParentId());
        while (parent != null) {
            if (!StringUtils.isEmpty(parent.getIdentity())) {
                s.insert(0, parent.getIdentity() + ":");
                hasResourceIdentity = true;
            }
            parent = findOne(parent.getParentId());
        }

        // 如果用户没有声明 资源标识 且父也没有，那么就为空
        if (!hasResourceIdentity) {
            return "";
        }

        // 如果最后一个字符是: 因为不需要，所以删除之
        int length = s.length();
        if (length > 0 && s.lastIndexOf(":") == length - 1) {
            s.deleteCharAt(length - 1);
        }

        // 如果有儿子 最后拼一个*
        boolean hasChildren = false;
        for (Resource r : findAll()) {
            if (resource.getId().equals(r.getParentId())) {
                hasChildren = true;
                break;
            }
        }
        if (hasChildren) {
            s.append(":*");
        }

        return s.toString();
    }

    public List<Menu> findMenus(User user) {

        Searchable searchable = Searchable.newSearchable().addSearchFilter("show", SearchOperator.eq, true)//
        .addSort(new Sort(Sort.Direction.DESC, "parentId", "weight"));

        List<Resource> resources = findAllWithSort(searchable);
        Set<String> userPermissions = userAuthService.findStringPermissions(user);
        Iterator<Resource> iter = resources.iterator();

        while (iter.hasNext()) {
            if (!hasPermission(iter.next(), userPermissions)) {
                iter.remove();
            }
        }
        return convertToMenus(resources);
    }

    /**
     * @return
     */
    public List<Menu> findcombotrees() {
        Searchable searchable = Searchable.newSearchable().addSort(new Sort(Sort.Direction.DESC, "parentId", "weight"));
        List<Resource> resources = findAllWithSort(searchable);
        return convertToMenus(resources);
    }

    public List<Treegrid> findTreegrids() {

        Searchable searchable = Searchable.newSearchable().addSort(new Sort(Sort.Direction.DESC, "parentId", "weight"));

        List<Resource> resources = findAllWithSort(searchable);
        return convertToTreegrids(resources);
    }

    /**
     * 将resources对象转化为treegrid
     * 
     * @param resources
     * @return
     */
    @SuppressWarnings("unchecked")
    private static List<Treegrid> convertToTreegrids(List<Resource> resources) {

        if (resources.size() == 0) {
            return Collections.EMPTY_LIST;
        }

        Treegrid root = convertToTreegrid(resources.remove(resources.size() - 1));
        recursiveTreegrid(root, resources);
        List<Treegrid> treegrids = root.getChildren();
        removeNoLeafTreegrid(treegrids);

        return treegrids;
    }

    /**
     * @param treegrids
     */
    private static void removeNoLeafTreegrid(List<Treegrid> treegrids) {
        if (treegrids.size() == 0) {
            return;
        }
        for (int i = treegrids.size() - 1; i >= 0; i--) {
            Treegrid m = treegrids.get(i);
            removeNoLeafTreegrid(m.getChildren());
            if (!m.isHasChildren() && StringUtils.isEmpty(m.getUrl())) {
                treegrids.remove(i);
            }
        }

    }

    /**
     * @param root
     * @param resources
     */
    private static void recursiveTreegrid(Treegrid treegrid, List<Resource> resources) {
        for (int i = resources.size() - 1; i >= 0; i--) {
            Resource resource = resources.get(i);
            if (resource.getParentId().equals(treegrid.getId())) {
                treegrid.getChildren().add(convertToTreegrid(resource));
                resources.remove(i);
            }
        }

        for (Treegrid subMenu : treegrid.getChildren()) {
            recursiveTreegrid(subMenu, resources);
        }
    }

    private boolean hasPermission(Resource resource, Set<String> userPermissions) {
        String actualResourceIdentity = findActualResourceIdentity(resource);
        if (StringUtils.isEmpty(actualResourceIdentity)) {
            return true;
        }

        for (String permission : userPermissions) {
            if (hasPermission(permission, actualResourceIdentity)) {
                return true;
            }
        }

        return false;
    }

    private boolean hasPermission(String permission, String actualResourceIdentity) {

        // 得到权限字符串中的 资源部分，如a:b:create --->资源是a:b
        String permissionResourceIdentity = permission.substring(0, permission.lastIndexOf(":"));

        // 如果权限字符串中的资源 是 以资源为前缀 则有权限 如a:b 具有a:b的权限
        if (permissionResourceIdentity.startsWith(actualResourceIdentity)) {
            return true;
        }

        // 模式匹配
        WildcardPermission p1 = new WildcardPermission(permissionResourceIdentity);
        WildcardPermission p2 = new WildcardPermission(actualResourceIdentity);

        return p1.implies(p2) || p2.implies(p1);
    }

    @SuppressWarnings("unchecked")
    public static List<Menu> convertToMenus(List<Resource> resources) {

        if (resources.size() == 0) {
            return Collections.EMPTY_LIST;
        }

        Menu root = convertToMenu(resources.remove(resources.size() - 1));
       
        recursiveMenu(root, resources);
        List<Menu> menus = root.getChildren();
        removeNoLeafMenu(menus);
        return menus;
    }

    private static void removeNoLeafMenu(List<Menu> menus) {
        if (menus.size() == 0) {
            return;
        }
        for (int i = menus.size() - 1; i >= 0; i--) {
            Menu m = menus.get(i);
            removeNoLeafMenu(m.getChildren());
            if (!m.isHasChildren() && StringUtils.isEmpty(m.getUrl())) {
                menus.remove(i);
            }
        }
    }

    private static void recursiveMenu(Menu menu, List<Resource> resources) {
        for (int i = resources.size() - 1; i >= 0; i--) {
            Resource resource = resources.get(i);
            if (resource.getParentId().equals(menu.getId())) {
                menu.getChildren().add(convertToMenu(resource));
                resources.remove(i);
            }
        }

        for (Menu subMenu : menu.getChildren()) {
            recursiveMenu(subMenu, resources);
        }
    }

    private static Menu convertToMenu(Resource resource) {
        return new Menu(resource.getId(), resource.getName(), resource.getIcon(), resource.getUrl());
    }

    private static Treegrid convertToTreegrid(Resource resource) {
        return new Treegrid(resource.getId(), resource.getName(), resource.getIdentity(), resource.getIcon(),
                            resource.getUrl(), resource.getShow());
    }

}
